package com.hjk.waibao.mj.render;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.jfinal.kit.StrKit;
import com.jfinal.render.Render;
import com.jfinal.render.RenderException;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

public class QrCodeWithBackgroundRender extends Render {

    private static final MatrixToImageConfig DEFAULT_CONFIG = new MatrixToImageConfig();

    private String content;
    private int width;
    private int height;
    private ErrorCorrectionLevel errorCorrectionLevel;

    /**
     * 构造方法，经测试不指定纠错参数时，默认使用的是 'L' 最低级别纠错参数
     *
     * @param content 二维码携带内容
     * @param width   二维码宽度
     * @param height  二维码高度
     */
    public QrCodeWithBackgroundRender(String content, int width, int height) {
        init(content, width, height, null);
    }

    private void init(String content, int width, int height, ErrorCorrectionLevel errorCorrectionLevel) {
        if (StrKit.isBlank(content)) {
            throw new IllegalArgumentException("content 不能为空");
        }
        if (width < 0 || height < 0) {
            throw new IllegalArgumentException("width 与 height 不能小于 0");
        }
        this.content = content;
        this.width = width;
        this.height = height;
        this.errorCorrectionLevel = errorCorrectionLevel;
    }

    @Override
    public void render() {
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/png");

        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        // 去掉白色边框，极度重要，否则二维码周围的白边会很宽
        hints.put(EncodeHintType.MARGIN, 0);
        if (errorCorrectionLevel != null) {
            hints.put(EncodeHintType.ERROR_CORRECTION, errorCorrectionLevel);
        }

        try {
            QRCodeWriter writer = new QRCodeWriter();
            BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);

            // 经测试 200 X 200 大小的二维码使用 "png" 格式只有 412B，而 "jpg" 却达到 15KB
            String path = request.getSession().getServletContext().getRealPath("/static/QrCodeImg/logo.png");
            overlapImage(bitMatrix, "png", response.getOutputStream(), path);
        } catch (Exception e) {
            throw new RenderException(e);
        }
    }

    /**
     * 将照片logo添加到二维码中间
     *
     * @param matrix
     * @param format
     * @param stream
     * @param logoPath
     * @throws IOException
     */
    public void overlapImage(BitMatrix matrix, String format, OutputStream stream, String logoPath) throws IOException {
        BufferedImage image = MatrixToImageWriter.toBufferedImage(matrix, DEFAULT_CONFIG);
        BufferedImage logo = ImageIO.read(new File(logoPath));
        Graphics2D g = image.createGraphics();
        // 考虑到logo照片贴到二维码中，建议大小不要超过二维码的1/5;
        int width = image.getWidth() / 3;
        int height = image.getHeight() / 3;
        // logo起始位置，此目的是为logo居中显示
        int x = (image.getWidth() - width) / 2;
        int y = (image.getHeight() - height) / 2;
        // 绘制图
        g.drawImage(logo, x, y, width, height, null);
        g.dispose();// 清理内存中的图片，返还内存给系统
        // 输出二维码
        ImageIO.write(image, format, stream);
    }
}
